from flask import current_app, request
from enums.vis_type_enum import VisTypeEnum
from enums.yes_no_enum import YesNoEnum
from mauth.login_user_holder import LoginUserHolder
from mauth.mtoken import TokenStrategyFactory
from mexception import AssertTool, GlobalErrorEnum
from models.vis_log import VisLog
from services.enums.user_error_enum import UserErrorEnum
from services.vis_log_service import VisLogService
from tools import get_client_ip, md5_encrypt, parse_user_agent
from decorators import Transactional

from models.user import User
from models.user_role import UserRole
from services.rbac_service import RbacService
from datetime import datetime, timedelta
class AuthService():
    """
    权限模块业务处理类
    """
    def __init__(self, db=None):
        if db is not None:
            self.db = db
        else:
            from models import db
            self.db = db
    @Transactional()
    def login(self, form):
        userName = form.userName.data
        password = form.password.data
        # 先根据用户名查
        u = self.db.session.query(User).filter(User.userName == userName).first()
        if u is None:
          # 根据手机号查
          u = self.db.session.query(User).filter(User.mobilePhone == userName).first()
        if u is None:
             # 用户不存在
             VisLogService(model=VisLog).save_vis_log(visType=VisTypeEnum.LOGIN, account=userName, success='N', message='登录失败，用户名不存在')
             AssertTool.raise_biz(UserErrorEnum.USER_NOT_EXIST)
        if u.isLocked == YesNoEnum.YES.code:
             VisLogService(model=VisLog).save_vis_log(visType=VisTypeEnum.LOGIN, account=userName, success='N', message='登录失败，用户名已被锁定')
             AssertTool.raise_biz(UserErrorEnum.USER_NOT_EXIST)
        salt = u.salt
        dbPassword = u.password
        md5Password = md5_encrypt(password+salt)
        if md5Password != dbPassword:
             VisLogService(model=VisLog).save_vis_log(visType=VisTypeEnum.LOGIN, account=userName, success='N', message='登录失败，密码错误')
             AssertTool.raise_biz(UserErrorEnum.USER_NOT_EXIST)
        # token存储
        token_strategy = TokenStrategyFactory.get_instance()
        tokenData = token_strategy.set(self.to_login_user(u))
        res = {
            "userId": str(u.id),
            "token": tokenData['token']
        }
        VisLogService(model=VisLog).save_vis_log(visType=VisTypeEnum.LOGIN, account=userName, success='Y', message='登录成功')
        return res
    @Transactional()
    def logout(self):
        VisLogService(model=VisLog).save_vis_log(visType=VisTypeEnum.LOGIN, account=LoginUserHolder.get_user_name(), success='Y', message='登出成功')
        token_strategy = TokenStrategyFactory.get_instance()
        token = request.headers.get(token_strategy.TOKEN_KEY, "")
        token = token.replace('Bearer ', '')
        token_strategy.remove(token)
    def play_user(self, userId):
        """
        模拟用户登录
        """
        user = self.db.session.query(User).filter(User.id == userId).first()
        if user is None:
            AssertTool.raise_biz(GlobalErrorEnum.GL99999999)
        currentUser = LoginUserHolder.get()
        loginUser = self.to_login_user(user)
        if loginUser.get('superAdmin') == True and currentUser.get('superAdmin') == False:
            # 非超级管理员不能扮演超级管理员
            AssertTool.raise_biz(GlobalErrorEnum.GL99999999)
        # 追加扮演用户信息
        loginUser['ext'] = {
            'playerToken': currentUser.get('token'),
            'playerUserId': currentUser.get('token'),
            'playUserAccount': currentUser.get('userName'),
            'isPlayer': True
        }
        loginUser['playerToken'] = currentUser['token']
        # token存储
        token_strategy = TokenStrategyFactory.get_instance()
        tokenData = token_strategy.set(loginUser)
        res = {
            "userId": loginUser['userId'],
            "token": tokenData['token']
        }
        return res
    def un_play_user(self):
        """
        取消扮演用户
        """
        currentUser = LoginUserHolder.get()
        userId = currentUser.get('userId')
        token = currentUser.get('playerToken')
        self.logout()
        return {
            'userId': userId,
            'token': token
        }
    def to_login_user(self, u):
        """
        用户信息转成登录用户信息
        """
        userRoleList = self.db.session.query(UserRole).filter(UserRole.userId == u.id)
        roleIds = [ur.roleId for ur in userRoleList]
        rbacService = RbacService()
        perms = ['admin']
        if u.adminType != 1:
            perms = rbacService.get_perm_in_cache(roleIds, 'platform')
        now = datetime.now()
        timeout = current_app.config.get('TOKEN_EXPIRE_TIMEOUT')
        userAgentStr = request.headers.get('User-Agent')
        userAgentDict = parse_user_agent(userAgentStr)
        os = userAgentDict.get('os')
        browser = userAgentDict.get('browser')
        ip = get_client_ip(request)
        loginUser = {
            "id": str(u.id),
            "userId": str(u.id),
            "userName": u.userName,
            "realName": u.realName,
            "perms": perms,
            "superAdmin": u.adminType == 1,
            "roleIds": roleIds,
            "loginTime": now.strftime("%Y-%m-%d %H:%M:%S"),
            "expireTime": (now + timedelta(seconds=timeout)).strftime("%Y-%m-%d %H:%M:%S"),
            'timeout': str(timeout),
            'loginIp': ip,
            'os': os,
            'loginBrowser': browser
        }
        return loginUser